﻿// 模板.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include<cmath>
#include <opencv2/opencv.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>

using namespace std;
using namespace cv;

#define PI 3.14
#define e 2.71
#define sigma 1
#define sigmad 500

double a[30][30] = { 0 };
double b[30][30] = { 0 };
/*******************************高斯函数*************************/
//（高斯）相邻方格空间距离利用高斯二维公式后的权重(未归一化)
double gaussion_sum(int x,int y)
{
	double total = 0;
	total = pow(e, -((x*x+y*y)/ 2 / sigma / sigma)) / (2 * PI * sigma * sigma);
	return total;
}
//计算3x3高斯模板的权重
void caclute()
{
	double sum_correct = 0;
	for (int i = 0; i <3 ; i++)
	{
		for (int j = 0; j <3; j++)
		{
			sum_correct = sum_correct +gaussion_sum(i, j);
		}
	}
	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 3; j++)
		{
			a[i][j] = gaussion_sum(i, j)/sum_correct;
		}
	}
}
//单通道3*3在新的权重下的总和(已归一化)
double gaussion_correct(Mat p,int x, int y)
{
	caclute();
	double sum_sum=0;
	int c = 0,d = 0;
	for (int i = x - 1; i <= x + 1; i++)
	{
		for (int j = y - 1; j <= y + 1; j++)
		{
			
			sum_sum = sum_sum +p.at<uchar>(i, j) *a[c][d];
			d++;
		}
		c++;
		d = 0;
	}
	c = d = 0;
	return sum_sum;
}
//多通道3X3矩阵中各个像素加权后的值(高斯)
double gaussion_value1(Mat& p, int x, int y, int k)
{
	caclute();
	double sum_sum = 0, weight = 0;
	int c = 0, d = 0;
	for (int i = x - 1; i <= x + 1; i++)
	{
		for (int j = y - 1; j <= y + 1; j++)
		{

			sum_sum = sum_sum + p.at<Vec3b>(i, j)[k] * a[c][d];
			d++;
		}
		c++;
		d = 0;
	}
	c = d = 0;
	return sum_sum;
}
/*****************************************************************/

/*************************双边函数************************************/
//（双边）相邻方格像素差值利用高斯二维公式后的权重(未归一化)
double bilateral_sum(uchar x)
{
	double total = 0;
	total = pow(e, -((x * x ) / (2*sigmad*sigmad)));
	return total;
}
//（双边）相邻方格空间距离利用高斯二维公式后的权重(未归一化)
double gaussion_sum0(uchar x)
{
	double total = 0;
	total = pow(e, -(x * x)) / (2  * sigma * sigma);
	return total;
}
//双边滤波的像素差值的权重（已归一化）
void bilate_value(Mat p, int x, int y)
{
	double sum_correct = 0;
	int m = 0, n = 0;
	for (int i = x - 1; i <= x + 1; i++)
	{
		for (int j = y - 1; j <= y + 1; j++)
		{
			uchar f = p.at<uchar>(i, j) - p.at<uchar>(x, y);
			b[m][n] = f;
			n++;
		}
		m++;
	}
	m = n = 0;
}
//双边滤波的3*3各个权重
void bilateral_caclute(Mat p, int x, int y)
{
	double sum_correct = 0;
	int m = 0, n = 0;
	for (int i = x - 1; i <= x + 1; i++)
	{
		for (int j = y - 1; j <= y + 1; j++)
		{
			b[m][n] = gaussion_sum0(x - i)+ gaussion_sum0(y - j);
			n++;
		}
		m++;
	}
	m = n = 0;
}
//每个方格单通道在新的权重下的总和(已归一化)
double bilateral_correct(Mat p, int x, int y)//返回的是公式
{
	bilateral_caclute(p,x,y);
	bilate_value(p,x,y);
	double sum_sum = 0;
	double sum_mother = 0;
	int c = 0, d = 0;
	for (int i = x - 1; i <= x + 1; i++)
	{
		for (int j = y - 1; j <= y + 1; j++)
		{
			for (int s = i - 1; s <= i + 1; s++)
			{
				for (int g = j - 1; g <= j + 1; g++)
				{
					sum_sum = sum_sum + p.at<uchar>(x, y) * gaussion_sum0(i-s)*gaussion_sum0(j-g) * bilateral_sum(b[c][d]);
					sum_mother = sum_mother + gaussion_sum0(i - s)* gaussion_sum0(j - g) * bilateral_sum(b[c][d]);
					d++;
				}
				c++;
			}
			c = d = 0;
		}

	}
	c = d = 0;
	return (sum_sum/sum_mother);
}
//多通道3X3矩阵中各个像素加权后的值(双边)
double bilateral_value1(Mat& p, int x, int y, int k)
{
	bilateral_caclute(p, x, y);
	bilate_value(p, x, y);
	double sum_sum = 0;
	double sum_mother = 0;
	int c = 0, d = 0;
	for (int i = x - 1; i <= x + 1; i++)
	{
		for (int j = y - 1; j <= y + 1; j++)
		{

			for (int s = i - 1; s <= i + 1; s++)
			{
				for (int g = j - 1; g <= j + 1; g++)
				{
					sum_sum = sum_sum + p.at<Vec3b>(x, y)[k] * gaussion_sum0(i - s)* gaussion_sum0(j - g) * bilateral_sum(b[c][d]);
					sum_mother = sum_mother + gaussion_sum0(i - s)* gaussion_sum0(j - g) * bilateral_sum(b[c][d]);
					d++;
				}
				c++;
			}
			c = d = 0;
		}
	}
	return (sum_sum / sum_mother);
}
/****************************************************************/

/********************************均值函数************************************/
//多通道3X3矩阵中各个像素的平均值(均值)
int sum_value(Mat &picture,int a,int b,int x)
{
	int sum=0;
	for (int i = a - 1; i <= a + 1; i++)
	{
		for (int j = b - 1; j <= b + 1; j++)
		{
			sum = sum +picture.at<Vec3b>(i, j)[x];
		}
	}
	sum = sum / 9;
	return sum;
}
//单通道3X3矩阵中各个像素的平均值（均值）
int sum_value(Mat&p_cinicture, int a, int b)
{
	int sum = 0;
	for (int i = a - 1; i <= a + 1; i++)
	{
		for (int j = b - 1; j <= b + 1; j++)
		{
			sum = sum +p_cinicture.at<uchar>(i, j);
		}
	}
	sum = sum / 9;
	return sum;
}
/***************************************************************************/


//均值滤波函数
static void average_wave(Mat& src, Mat& dst)
{
	//3x3的核
	int row = src.rows;//行
	int col = src.cols;//列
	int num = src.channels();//通道数
	if(num==1)//单通道
	{
		for (int i = 0; i < row; i++)//使效果图和原图一样
		{
			for (int j = 0; j < col; j++)
			{
				dst.at<uchar>(i, j) = src.at<uchar>(i, j);
			}
		}
		for (int i = 0; i < row; i++)//在效果图上滤波
		{
			for (int j = 0; j < col; j++)
			{
				if (i != 0 && j != 0 && i != row - 1 && j != col - 1)
				{
					dst.at<uchar>(i, j) = sum_value(dst, i, j);
				}
			}
		}
	}
	if (num == 3)//多通道
	{
		for (int i = 0; i < row; i++)
		{
			for (int j = 0; j < col; j++)
			{
				dst.at<Vec3b>(i, j)[0] = src.at<Vec3b>(i, j)[0];
				dst.at<Vec3b>(i, j)[1] = src.at<Vec3b>(i, j)[1];
				dst.at<Vec3b>(i, j)[2] = src.at<Vec3b>(i, j)[2];
			}
		}
		for (int i = 0; i < row; i++)
		{
			for (int j =0 ; j < col; j++)
			{
				if (i != 0 && j != 0&&i!=row-1&&j!=col-1)
				{
					dst.at<Vec3b>(i, j)[0] = sum_value(dst, i, j, 0);
					dst.at<Vec3b>(i, j)[1] = sum_value(dst, i, j, 1);
					dst.at<Vec3b>(i, j)[2] = sum_value(dst, i, j, 2);
				}
			}
		}
	}
}
//高斯滤波函数
static void gauss_wave(Mat& src, Mat& dst)
{
	caclute();
	int row = src.rows;//行
	int col = src.cols;//列
	int num = src.channels();//通道数
	if (num == 1)//单通道
	{
		for (int i = 0; i < row; i++)//使效果图和原图一样
		{
			for (int j = 0; j < col; j++)
			{
				dst.at<uchar>(i, j) = src.at<uchar>(i, j);
			}
		}
		for (int i = 0; i < row; i++)//在效果图上滤波
		{
			for (int j = 0; j < col; j++)
			{
				if (i != 0 && j != 0 && i != row - 1 && j != col - 1)
				{
					dst.at<uchar>(i, j) = (uchar)gaussion_correct(dst,i, j);	
				}
			}
		}
	}
	if (num == 3)//多通道
	{
		for (int i = 0; i < row; i++)//使效果图和原图一样
		{
			for (int j = 0; j < col; j++)
			{
				dst.at<Vec3b>(i, j)[0] = src.at<Vec3b>(i, j)[0];
				dst.at<Vec3b>(i, j)[1] = src.at<Vec3b>(i, j)[1];
				dst.at<Vec3b>(i, j)[2] = src.at<Vec3b>(i, j)[2];
			}
		}
		for (int i = 0; i < row; i++)
		{
			for (int j = 0; j < col; j++)
			{
				if (i != 0 && j != 0 && i != row - 1 && j != col - 1)
				{
					dst.at<Vec3b>(i, j)[0] = (uchar)gaussion_value1(dst, i, j, 0);
					dst.at<Vec3b>(i, j)[1] = (uchar)gaussion_value1(dst, i, j, 1);
					dst.at<Vec3b>(i, j)[2] = (uchar)gaussion_value1(dst, i, j, 2);
				}
			}
		}
	}

}
//双边滤波函数
static void bilateral_wave(Mat& src, Mat& dst)
{
	int row = src.rows;//行
	int col = src.cols;//列
	int num = src.channels();//通道数
	if (num == 1)//单通道
	{
		for (int i = 0; i < row; i++)//使效果图和原图一样
		{
			for (int j = 0; j < col; j++)
			{
				dst.at<uchar>(i, j) = src.at<uchar>(i, j);
			}
		}
		for (int i = 0; i < row; i++)//在效果图上滤波
		{
			for (int j = 0; j < col; j++)
			{
				if (i != 0 && j != 0 && i != row - 1 && j != col - 1)
				{
					dst.at<uchar>(i, j) = (uchar)bilateral_correct(dst, i, j);
				}
			}
		}
	}
	if (num == 3)//多通道
	{
		for (int i = 0; i < row; i++)//使效果图和原图一样
		{
			for (int j = 0; j < col; j++)
			{
				dst.at<Vec3b>(i, j)[0] = src.at<Vec3b>(i, j)[0];
				dst.at<Vec3b>(i, j)[1] = src.at<Vec3b>(i, j)[1];
				dst.at<Vec3b>(i, j)[2] = src.at<Vec3b>(i, j)[2];
			}
		}
		for (int i = 0; i < row; i++)
		{
			for (int j = 0; j < col; j++)
			{
				if (i != 0 && j != 0 && i != row - 1 && j != col - 1)
				{

					dst.at<Vec3b>(i, j)[0] = (uchar)bilateral_value1(dst, i, j, 0);
					dst.at<Vec3b>(i, j)[1] = (uchar)bilateral_value1(dst, i, j, 1);
					dst.at<Vec3b>(i, j)[2] = (uchar)bilateral_value1(dst, i, j, 2);
				}
			}
		}
	}
}



int main()
{
	Mat p_cin,p_cout;
	p_cin = imread("C:/Users/郭睿豪/Pictures/图片库/20.jpg",1);
	p_cout = imread("C:/Users/郭睿豪/Pictures/图片库/2000.jpg",1);
	imshow("原图",p_cin);
	average_wave(p_cin,p_cout);
	//gauss_wave(p_cin,p_cout);
	//bilateral_wave(p_cin,p_cout);
	namedWindow("单/多通道-效果图", WINDOW_NORMAL);
	imshow("单/多通道-效果图",p_cout);
	cout << "效果图生成成功！！！" << endl;
	waitKey(0);
}